package cn.clouds234.jschdemo;


import com.jcraft.jsch.*;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Vector;

/**
 * @author: clouds234
 * @date: 2022/4/14  17:24
 * ssh连接工具。用于连接服务器。
 */
public class JSchUtils {

	/**
	 连接使用属性
	 */
	private JSch jsch;
	private Session session;
	private ChannelSftp channelSftp;
	/**
	 * ChannelExec
	 *
	 * 对于ChannelExec,在调用connect()方法之前这个命令提供了setCommand()方法，并且这些命令作为输入将以输入流的形式被发送出去。
	 * （通常，你只能有调用setCommand()方法一次，多次调用只有最后一次生效），
	 * 但是你可以使用普通shell的分隔符（&，&&，|，||，; , \n, 复合命令）来提供多个命令。
	 * 这就像在你本机上执行一个shell脚本一样（当然，如果一个命令本身就是个交互式shell，这样就像ChannelShell）
	 */
	private ChannelExec channelExec;
	/**
	 * ChannelShell
	 *
	 * 对于ChannelShell，以输入流的形式，提供命令和输入这些命令，这就像在本地计算机上使用交互式shell（它通常用于：交互式使用）
	 */
	private ChannelShell channelShell;

	// ===========连接主机==================
	/**
	 * 使用pvk连接ssh服务器。
	 * @param user
	 * @param keyPath
	 * @param host
	 * @param port
	 * @throws JSchException
	 */
	public void connectByPvk(String user, String keyPath, String host, int port) throws JSchException {
		// 创建JSch对象
		jsch = new JSch();

		// 设置私钥
		jsch.addIdentity(keyPath);
		// 根据用户名、主机ip、端口号获取一个Session对象
		session = jsch.getSession(user, host, port);
		session.setConfig("StrictHostKeyChecking", "no");
//		session.setConfig("userauth.gssapi-with-mic", "no");
		// 设置超时
		session.setTimeout(5000);
		// 通过Session建立连接
		session.connect();
	}


	public void connectByPvk(String user, byte[] prvKey, String host, int port) throws JSchException {
		// 创建JSch对象
		jsch = new JSch();
		// 设置私钥
		jsch.addIdentity("id_rsa", prvKey, null, null);
		// 根据用户名、主机ip、端口号获取一个Session对象
		session = jsch.getSession(user, host, port);
		session.setConfig("userauth.gssapi-with-mic", "no");
		session.setConfig("StrictHostKeyChecking", "no");
		// 设置超时
		session.setTimeout(5000);
		// 通过Session建立连接
		session.connect();
	}

	/**
	 * 使用用户名密码连接ssh服务器。
	 * @param user
	 * @param passwd
	 * @param host
	 * @param port
	 * @throws JSchException
	 */
	public void connectByPassword(String user, String passwd, String host, int port) throws JSchException {
		jsch = new JSch();
		// 根据用户名、主机ip、端口号获取一个Session对象
		session = jsch.getSession(user, host, port);
		// 设置密码
		session.setPassword(passwd);
		// 关闭验证公私钥的过程。
		session.setConfig("StrictHostKeyChecking", "no");
		// 设置超时
		session.setTimeout(10 * 1000);
		// 通过Session建立连接
		session.connect();
	}

	// =================执行命令=====================
	/**
	 * 一次性执行命令。
	 * @param baseDir
	 * @param command
	 * @return
	 * @throws JSchException
	 * @throws IOException
	 */
	public String exec(String baseDir, String command) throws JSchException, IOException {
		try {
			if (command != null) {
				// ！！！此处需要注意，先设置命令，然后在连接通道；
				getChannelExec();
				InputStream in = channelExec.getInputStream();
				InputStream extIn = channelExec.getExtInputStream();
				channelExec.setCommand("cd " + baseDir + ";" + command);
				channelExec.connect();
				return Objects.requireNonNull(getRes(in, extIn)).toString();
			}
		} catch (IOException e) {
			throw new IOException(e);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		} finally {
			channelExec.disconnect();
			channelExec = null;
		}
		return null;
	}
	/**
	 * @param baseDir
	 * @param splitStr
	 * @param cmds
	 * @return String
	 * @throws JSchException
	 * @throws IOException
	 * @throws InterruptedException
	 * @description 一次性执行多条命令
	 * @author wyf
	 * @date 2023/12/25 19:52
	 */
	public String execCmd(String baseDir, String splitStr, List<String> cmds) throws JSchException, IOException, InterruptedException {
		try {
			if (cmds != null) {
				// ！！！此处需要注意，先设置命令，然后在连接通道；
				channelExec = (ChannelExec) session.openChannel("exec");
				InputStream in = channelExec.getInputStream();
				InputStream extIn = channelExec.getExtInputStream();
				// !!!非shell登录模式不加载/etc/profile文件的环境变量。所以需要手动加入
				StringBuilder cmdBud = new StringBuilder("cd " + baseDir);
				for (String s : cmds) {
					cmdBud.append(splitStr).append(s);
				}
				channelExec.setCommand(cmdBud.toString());
				channelExec.connect();

				// 等待执行完成
				StringBuilder res = getRes(in, extIn);
				return res.toString();
			}
		} catch (IOException e) {
			throw new IOException(e);
		} finally {
			channelExec.disconnect();
			channelExec = null;
		}
		return null;
	}
	/**
	 * 使用交互模式执行命令。
	 * @param dir
	 * @param cmds
	 * @return
	 * @throws JSchException
	 * @throws IOException
	 */
	public BufferedReader shell(String dir, String... cmds) throws JSchException, IOException {
		if (StringUtils.isEmpty(dir) || cmds.length < 1) {
			return null;
		}
		connectChannelShell();
		//获取输入
		InputStreamReader inputStreamReader = new InputStreamReader(channelShell.getInputStream());
		// 用于接收返回信息
		BufferedReader input = new BufferedReader(inputStreamReader);

		//输出
		PrintWriter printWriter = new PrintWriter(channelShell.getOutputStream());
		printWriter.print("cd ");
		printWriter.println(dir);
		for (String cmd : cmds) {
			printWriter.println(cmd);
		}
//		printWriter.println("exit");
		printWriter.flush();
		// 将返回结果的流返回
//		return;
//		String line;
//		while ((line = input.readLine()) != null) {
//			System.out.println(line);
//		}

		return input;
	}

	// =========以下为文件操作===========
	/**
	 * 上传文件
	 *
	 * @param directory  上传的目录
	 * @param uploadFile 要上传的文件
	 * @throws JSchException
	 * @throws SftpException
	 * @throws FileNotFoundException
	 */
	public void upload(String directory, String uploadFile) throws JSchException, FileNotFoundException, SftpException {
		connectChannelSftp();
		List<String> paths = formatPath(directory);
		if (!mkdir(paths.get(0))) {
			throw new SftpException(1, "can not mkdir " + paths.get(0));
		}

//        channelSftp.cd(directory);
		File file = new File(uploadFile);
		FileInputStream fileInputStream = new FileInputStream(file);
		String home = channelSftp.getHome();
		channelSftp.put(uploadFile, directory);
//        channelSftp.put(fileInputStream, directory);
	}

	/**
	 * 下载文件
	 *
	 * @param src 源文件
	 * @param dst 目标文件
	 * @throws JSchException
	 * @throws SftpException
	 */
	public void download(String src, String dst) throws JSchException, SftpException {
		connectChannelSftp();
		List<String> paths = formatPath(dst);
		File dstDir = new File(paths.get(0));
		if (!dstDir.exists()) {
			dstDir.mkdirs();
		}
		// src linux服务器文件地址，dst 本地存放地址
		channelSftp.get(src, dst);
	}

	/**
	 *
	 * @description 重命名文件
	 * @param oldPath
	 * @param newPath
	 * @throws JSchException
	 * @throws SftpException
	 * @author wyf
	 * @date 2024/1/3 10:43
	 */
	public void rename(String oldPath, String newPath) throws JSchException, SftpException {
		connectChannelSftp();
		if (!dirOrFileExist(oldPath)) {
			throw new SftpException(1, "path not exist");
		}
		channelSftp.rename(oldPath, newPath);
	}

	/**
	 * 删除文件
	 *  不能删除目录。
	 * @param directory  要删除文件所在目录
	 * @param deleteFile 要删除的文件
	 * @throws SftpException
	 * @throws JSchException
	 */
	public void delete(String directory, String deleteFile) throws JSchException, SftpException {
		connectChannelSftp();
		channelSftp.cd(directory);

		channelSftp.rm(deleteFile);

	}

	/**
	 * 列出目录下的文件
	 * 每个文件对象为LsEntity。
	 * @param directory 要列出的目录
	 * @return
	 * @throws SftpException
	 * @throws JSchException
	 */
	public Vector listFiles(String directory) throws JSchException, SftpException {
		connectChannelSftp();
		return channelSftp.ls(directory);
	}

	/**
	 * 根据路径创建文件夹.
	 * mkdir(null)      = true
	 *   mkdir("")        = true
	 *   mkdir("bob")     = true
	 *   mkdir("/bob") = true
	 * @param dir 路径 必须是 /xxx/xxx/ 不能就单独一个/
	 * @throws Exception 异常
	 */
	public boolean mkdir(final String dir) throws SftpException, JSchException {
		// 连接sftp通道
		connectChannelSftp();
		// 如果路径为空。结果为创建成功。
		if (StringUtils.isBlank(dir)) {
			return true;
		}
		// 替换路径分隔符。将“\”换成“/”
		String md = dir.replaceAll("\\\\", "/");
		// 定义根路径。拥有判断是否是绝对路径。
		String base = "";
		// 如果是绝对目录
		if (md.startsWith("/")){
			base = "/";
		}
		// 拆分多级路径
		String[] dirArr = md.split("/");
		// 循环创建多级路径
		for (String d : dirArr) {
			base += d + "/";
			if (!dirOrFileExist(base)) {
				channelSftp.mkdir(base);
			}
		}
		return true;

	}

	/**
	 * 关闭所有通道。
	 * 关于Session的使用，创建连接后这个session是一直可用的，所以不需要关闭。由Session中open的Channel在使用后应该关闭。
	 */
	public void closeChannel() {
		if (channelExec != null) {
			channelExec.disconnect();
		}
		if (channelSftp != null) {
			channelSftp.disconnect();
		}
		if (channelShell != null) {
			channelShell.disconnect();
		}

	}

	/**
	 * 当不需要此服务器连接时，关闭会话。
	 * 关于Session的使用，创建连接后这个session是一直可用的，所以不需要关闭。由Session中open的Channel在使用后应该关闭。
	 */
	public void closeSession(){
		if (session != null) {
			session.disconnect();
		}
	}


	// =================== 以下为私有方法 =================================


	/**
	 * 处理exec通道返回的结果。
	 * 结果为多行字符串。
	 * 第一行是通道退出状态码。
	 * 第二行开始是通道返回的其他信息。
	 * @description
	 * @param in
	 * @param extIn
	 * @return StringBuilder
	 * @throws InterruptedException
	 * @throws IOException
	 * @author wyf
	 * @date 2024/5/10 10:04
	 */
	private StringBuilder getRes(InputStream in, InputStream extIn) throws InterruptedException, IOException {
		// 等待执行完成
		Integer elapsedTimeMeter = 0;
		while (!channelExec.isClosed()) {
			Thread.sleep(1000);
			elapsedTimeMeter++;

			//超过三百秒，抛出异常
			if (elapsedTimeMeter > 300) {
				return null;
			}
		}
		// 获取通道退出状态
		int exitStatus = channelExec.getExitStatus();
		StringBuilder res = new StringBuilder();
		res.append(exitStatus);
		// 增加通道返回信息
		BufferedReader extBuf = new BufferedReader(new InputStreamReader(extIn));
		BufferedReader inBuf = new BufferedReader(new InputStreamReader(in));
		String msg;
		while ((msg = extBuf.readLine()) != null) {
			res.append("\n").append(msg);
		}
		while ((msg = inBuf.readLine()) != null) {
			res.append("\n").append(msg);
		}
		return res;
	}

	/**
	 * 判断文件夹是否存在.
	 *
	 * @param dir 文件夹路径， /xxx/xxx/
	 * @return 是否存在
	 */
	private boolean dirOrFileExist(final String dir) throws JSchException {
		connectChannelSftp();
		Vector vector;
		try {
			vector = channelSftp.ls(dir);
		} catch (SftpException e) {
			return false;
		}
		return null != vector;

	}

	/**
	 * 格式化路径.
	 *
	 * @param srcPath 原路径. /xxx/xxx/xxx.yyy 或 X:/xxx/xxx/xxx.yy
	 * @return list, 第一个是路径（/xxx/xxx/）,第二个是文件名（xxx.yy）
	 */
	private List<String> formatPath(final String srcPath) {
		List<String> list = new ArrayList<String>(5);
		String repSrc = srcPath.replaceAll("\\\\", "/");
		int firstP = repSrc.indexOf("/");
		int lastP = repSrc.lastIndexOf("/");
		String fileName = lastP + 1 == repSrc.length() ? "" : repSrc.substring(lastP + 1);
		String dir = firstP == -1 ? "" : repSrc.substring(0, lastP);
		dir = dir.length() == 1 ? dir : (dir + "/");
		list.add(dir);
		list.add(fileName);
		return list;
	}

	/**
	 * @Author: clouds234
	 * @Date: 2021/4/5 17:51
	 * @Method:getChannelSftp: 获取sftp通道；
	 * @Param:[]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void getChannelSftp() throws JSchException {
		if (channelSftp == null) {
			channelSftp = (ChannelSftp) session.openChannel("sftp");
		}
	}

	/**
	 * @Author: clouds234
	 * @Date: 2021/4/5 17:53
	 * @Method:getChannelExec: 获取命令执行通道；
	 * @Param:[]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void getChannelExec() throws JSchException {
		if (channelExec == null) {
			channelExec = (ChannelExec) session.openChannel("exec");
		}
	}

	/**
	 * @Author: clouds234
	 * @Date: 2021/4/5 17:54
	 * @Method:connectChannelSftp: 开启sftp通道；
	 * @Param:[]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void connectChannelSftp() throws JSchException {
		getChannelSftp();
		if (channelSftp.isConnected()) {
			return;
		}
		channelSftp.connect(5000);
	}
	/**
	 * @Author: clouds234
	 * @Date: 2021/4/9 15:20
	 * @Method:getChannelShell: 获取shell通道；
	 * @Param:[]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void getChannelShell() throws JSchException {
		if (channelShell == null) {
			channelShell = (ChannelShell) session.openChannel("shell");
		}
	}
	/**
	 * @Author: clouds234
	 * @Date: 2021/4/9 15:21
	 * @Method:connectChannelShell: 连接shell通道；
	 * @Param:[]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void connectChannelShell() throws JSchException {
		getChannelShell();
		if (channelShell.isConnected()) {
			return;
		}
			//通道连接 超时时间5s
		channelShell.connect(5000);
	}
	/**
	 * @Author: clouds234
	 * @Date: 2021/4/9 15:23
	 * @Method:shellChannelCommand: shell通道发送命令
	 * @Param:[channel, command] 通道，命令
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	private void shellChannelCommand(Channel channel, String command) throws IOException {
		if (channel != null) {
			OutputStream outputStream = channel.getOutputStream();
			outputStream.write(command.getBytes());
			outputStream.flush();
		}
	}



	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}

	/**
	 * @Author: clouds234
	 * @Date: 2021/4/5 14:48
	 * @Method:main: 测试功能
	 * @Param:[args]
	 * @Class:com.dap.cloud.framework.server.web.common.util.JSchUtils
	 * @Return:void
	 */
	public static void main(String[] args) {
			/*
	使用 JSch 时出现“无效私钥”

	发现根本原因是ssh私钥不匹配。异常仅发生在使用较新类型 ed25519 密钥的用户身上，该密钥输出此密钥标头：
	-----BEGIN OPENSSH PRIVATE KEY-----
	而不是那种 RSA ：
	-----BEGIN RSA PRIVATE KEY-----
	重新生成 RSA 密钥 ( ssh-keygen -t rsa )，使异常消失。
	如果您有 OpenSSH 7.8 及更高版本，您可能需要将 -m PEM 添加到生成命令中： ssh-keygen -t rsa -m PEM
	 */
		String prvKeyPem = "-----BEGIN RSA PRIVATE KEY-----\n" +
				"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\n" +
				"-----END RSA PRIVATE KEY-----";
		String pubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5xKvgwOuacHDLZKt6g056XpibtL7Y0fDCUbTiu8zW4fphQjQQiQ9pKEKmNK1qymxYGj/gWFfcpGr2nz7U1+iTITsRAvidV5J+7gI8Zr9uiOsD9cBIelk1wcBAbPpwXTybzem5hh9Ic/JnIjkiyqbl9j1h6/4aN8eM5HkgrSr6oZePGb9LxpsTfr6OqbwD3G8arcW1H6YtukSXBRlIFou1eDS1rVO8/FJqpRDtrQxOdDxMiFi6VRR+RdmhrS51ze3KdtZK/VNXvC6zT/HkDVDovjqj2ZqJkwC/z3+lGGq1j+7w5q4tW/q4F4ya10pDquo9Tklfon0B+DagYYXoZpkh clouds234@localhost.localdomain";
//		byte[] prvKey = prv_key.getBytes(StandardCharsets.UTF_8);
		byte[] prvKey = prvKeyPem.getBytes();
		JSchUtils jSchUtils = new JSchUtils();
		InputStream privKeyStream = new ByteArrayInputStream(prvKeyPem.getBytes());
		try {
			// 1.连接到指定的服务器
//			jSchUtils.connectByPassword("root", "Gientech2022!", "10.64.15.86", 22);
//            jSchUtils.connectByPvk("root", "F:/data/86rsa.txt", "10.64.15.86", 22);
            jSchUtils.connectByPvk("root", prvKey, "10.64.15.86", 22);

			// 2.执行相关的命令
//			jSchUtils.execCmd("","ifconfig;cd /home;ls");
//			BufferedReader ls = jSchUtils.exec("/home", "ls");
//			BufferedReader input = jSchUtils.shell("/home/clouds234", "ls >> test.txt", "sleep 5s", "date >> test.txt");
//			String line;
//			while ((line = input.readLine()) != null) {
//				System.out.println(line);
//			}
//			BufferedReader input2 = jSchUtils.shell("/home/clouds234", "ls >> test.txt", "sleep 5s", "date >> test.txt");
//			String line2;
//			while ((line2 = input2.readLine()) != null) {
//				System.out.println(line2);
//			}
			// 3.1上传文件,不能上传文件夹，上传目录必须存在；
//            String dstPath = "/home/clouds234_test/aaa/bbb/aa.pdf";
//            String filePath = "D:/10_work/aa.pdf";
//            jSchUtils.upload(dstPath, filePath);
			// 3.2下载文件
			// 需要测试Linux系统文件夹创建是否可用；
//            jSchUtils.download("/home/clouds234_test/happy.txt", "D:/10_work/aaa/bbb/happy1.txt");
			// 3.3 查看文件
//            Vector listFiles = jSchUtils.listFiles("/home/clouds234_test/");
//            for (Object o: listFiles){
//                ChannelSftp.LsEntry e = (ChannelSftp.LsEntry) o;
//                if (!e.getFilename().matches("\\.+")){
//                    System.out.println(e.getFilename());
//                    System.out.println(e.toString());
//                    // 结果如下：
//                    // aaa // filename
//                    // drwxr-xr-x    2 root     root            6 Apr  5 19:49 aaa // longname
//                    String longname = e.getLongname();
//                    String[] split = longname.split("\\s+");
//                    for (String s : split) {
//                        System.out.println(s);
//                    }
//                }
//            }
			// 3.4 重命名
//            jSchUtils.rename("/home/clouds234_test/bbbaa", "/home/clouds234_test/aaab");
			// 3.5 删除文件
//			jSchUtils.delete("/home/clouds234_test/", "a.txt");
			jSchUtils.connectChannelSftp();
			jSchUtils.channelSftp.cd("/home");
			Vector vector = jSchUtils.listFiles("/home");
			for (Object o : vector) {
				System.out.println(o);
			}
		} catch (Exception e) {
			// 实际使用时，分开不同的exception处理；这里为了测试简单；
			e.printStackTrace();

		} finally {
			jSchUtils.closeChannel();
			jSchUtils.closeSession();
		}
	}


}
